#ifndef __NOT_USE_GPU__

// path to cuda libarary
#include <cstdio>


#include "GPU_Convolution.h"

#ifndef APEX_CUDA_MATRIX_CUH
#define APEX_CUDA_MATRIX_CUH "../cuda_gpu/matrix/cuda_matrix.cuh"
#endif
#include APEX_CUDA_MATRIX_CUH


namespace gpu_tianqichen
{
	void convolution_v2h(
		Mat3D& DstH,
		const Mat3D& SrcV,
        const Mat4DBias& SrcMask){
        //init matrix 
        cuda_matrix::Mat3D d_dstH( DstH.z_max, DstH.y_max, DstH.x_max ); 
        cuda_matrix::Mat3D d_srcV( SrcV.z_max, SrcV.y_max, SrcV.x_max );
        cuda_matrix::Mat4DBias d_srcMask( SrcMask.mat.v_max,  SrcMask.mat.h_max, SrcMask.mat.y_max, SrcMask.mat.x_max );
        
        // allocate space
        cuda_matrix::mat_alloc_device( d_dstH );
        cuda_matrix::mat_alloc_device( d_srcV );
        cuda_matrix::mat_alloc_device( d_srcMask );
        // copy to GPU
        cuda_matrix::matcpy( d_srcV, SrcV , cudaMemcpyHostToDevice );
        cuda_matrix::matcpy( d_srcMask, SrcMask , cudaMemcpyHostToDevice );
        // run GPU function 
        cuda_matrix::conv2_r_valid<cuda_map::NONE,cuda_matrix::store_method::SAVE>( d_dstH , d_srcV, d_srcMask );
        
        // wait for computation to be complete 
        cudaThreadSynchronize();
        
        //copy back
        cuda_matrix::matcpy( DstH, d_dstH , cudaMemcpyDeviceToHost );
        // free space 
        cuda_matrix::mat_free_device( d_dstH );
        cuda_matrix::mat_free_device( d_srcV );
        cuda_matrix::mat_free_device( d_srcMask );        
    }

	void convolution_h2v(
		Mat3D& DstV,
		const Mat3D& SrcH,
        const Mat4DBias& SrcMask){
        //init matrix 
        cuda_matrix::Mat3D d_dstV( DstV.z_max, DstV.y_max, DstV.x_max ); 
        cuda_matrix::Mat3D d_srcH( SrcH.z_max, SrcH.y_max, SrcH.x_max );
        cuda_matrix::Mat4DBias d_srcMask( SrcMask.mat.v_max,  SrcMask.mat.h_max, SrcMask.mat.y_max, SrcMask.mat.x_max );
        
        // allocate space
        cuda_matrix::mat_alloc_device( d_dstV );
        cuda_matrix::mat_alloc_device( d_srcH );
        cuda_matrix::mat_alloc_device( d_srcMask );
        // copy to GPU
        cuda_matrix::matcpy( d_srcH, SrcH , cudaMemcpyHostToDevice );
        cuda_matrix::matcpy( d_srcMask, SrcMask , cudaMemcpyHostToDevice );
        // run GPU function 
        cuda_matrix::conv2_full<cuda_map::NONE,cuda_matrix::store_method::SAVE>( d_dstV , d_srcH, d_srcMask );
        
        // wait for computation to be complete 
        cudaThreadSynchronize();
        
        //copy back
        cuda_matrix::matcpy( DstV, d_dstV , cudaMemcpyDeviceToHost );
        // free space 
        cuda_matrix::mat_free_device( d_dstV );
        cuda_matrix::mat_free_device( d_srcH );
        cuda_matrix::mat_free_device( d_srcMask );        
    }

	void convolution_a2m(
		Mat4DBias& DstMask,
		const Mat3D& SrcV,
        const Mat3D& SrcH ){
        //init matrix 
        cuda_matrix::Mat3D d_srcV( SrcV.z_max, SrcV.y_max, SrcV.x_max ); 
        cuda_matrix::Mat3D d_srcH( SrcH.z_max, SrcH.y_max, SrcH.x_max );
        cuda_matrix::Mat4D d_dstMask( DstMask.mat.v_max,  DstMask.mat.h_max, DstMask.mat.y_max, DstMask.mat.x_max );
        
        // allocate space
        cuda_matrix::mat_alloc_device( d_srcV );
        cuda_matrix::mat_alloc_device( d_srcH );
        cuda_matrix::mat_alloc_device( d_dstMask );
        // copy to GPU
        cuda_matrix::matcpy( d_srcH, SrcH , cudaMemcpyHostToDevice );
        cuda_matrix::matcpy( d_srcV, SrcV , cudaMemcpyHostToDevice );
        // run GPU function 
        cuda_matrix::conv2_r_big_filter<cuda_map::NONE,cuda_matrix::store_method::SAVE>( d_dstMask , d_srcV, d_srcH );
        
        // wait for computation to be complete 
        cudaThreadSynchronize();
        
        //copy back
        cuda_matrix::matcpy( DstMask.mat , d_dstMask , cudaMemcpyDeviceToHost );
        // free space 
        cuda_matrix::mat_free_device( d_srcV );
        cuda_matrix::mat_free_device( d_srcH );
        cuda_matrix::mat_free_device( d_dstMask );   
    }
};

#endif
